#include "timeline.h"

#include <QGraphicsItemGroup>
#include <QGraphicsEllipseItem>
#include <QGraphicsSceneMouseEvent>

#include "positionpointeritem.h"

#include <QDebug>

const qreal SceneWidth = 1000;
const qreal SceneHeight = 40;

Timeline::Timeline(QObject *parent) :
    QGraphicsScene(parent),
    m_positionPointer(new PositionPointerItem), m_activeRangeBar(NULL), m_adjustingPosition(false)
{
    setSceneRect(0, 0, SceneWidth, SceneHeight);

    m_bar = addRect(0, SceneHeight / 2 - (OuterCircleDiameter + InnerCircleDiameter) / 2 / 2, SceneWidth, (OuterCircleDiameter + InnerCircleDiameter) / 2);

    m_positionBar = addRect(0, SceneHeight / 2 - (OuterCircleDiameter + InnerCircleDiameter) / 2 / 2, 0, (OuterCircleDiameter + InnerCircleDiameter) / 2);
    QLinearGradient linearGradient(0, 0, 0, 100);
    linearGradient.setColorAt(0.0, Qt::red);
    linearGradient.setColorAt(0.4, Qt::black);
    m_positionBar->setBrush(linearGradient);

    addItem(m_positionPointer);

    setPosition(0);

    connect(this, SIGNAL(selectionChanged()), this, SIGNAL(selectedMarkersChanged()));

    connect(&m_markerItemSignalMapper, SIGNAL(mapped(QObject*)), this, SLOT(markerXChanged(QObject*)));

    foreach(QGraphicsItem* item, items())
        item->setFlag(QGraphicsItem::ItemIsFocusable, false);
}

void Timeline::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
    if (m_bar->contains(event->scenePos()))
        m_adjustingPosition = true;

    QGraphicsScene::mousePressEvent(event);
}

void Timeline::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
    m_adjustingPosition = false;
    QGraphicsScene::mouseReleaseEvent(event);
}

void Timeline::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
    if (m_adjustingPosition)
    {
        qint64 newPos = fromSceneXPos(event->scenePos().x());
        if (newPos > m_length)
            newPos = m_length;

        if (newPos < 0)
            newPos = 0;

        setPosition(newPos);
        emit adjusted(newPos);
    }

    QGraphicsScene::mouseMoveEvent(event);
}

qreal Timeline::toSceneXPos(qint64 pos)
{
    return SceneWidth / m_length * pos;
}

qint64 Timeline::fromSceneXPos(qreal xPos)
{
    return xPos * m_length / SceneWidth;
}

void Timeline::setLength(qint64 length)
{
    m_length = length;
}

void Timeline::setPosition(qint64 position)
{
    m_positionPointer->setPos(int(toSceneXPos(position)), SceneHeight / 2);

    QRectF rect = m_positionBar->rect();
    rect.setWidth(toSceneXPos(position));
    m_positionBar->setRect(rect);
}

void Timeline::setMarkers(QList<Marker> markers)
{
    QList<MarkerItem*> removedMarkerItems = m_uuidMarkerItemMap.values();
    foreach(Marker marker, markers)
    {
        if (!m_uuidMarkerItemMap.contains(marker.uuid()))
        {
            MarkerItem* markerItem = new MarkerItem;
            addItem(markerItem);
            markerItem->setYPos(0);
            markerItem->setPos(int(toSceneXPos(marker.position())), 0);
            m_uuidMarkerItemMap[marker.uuid()] = markerItem;
            m_uuidMarkerMap[marker.uuid()] = marker;

            connect(markerItem, SIGNAL(xChanged()), &m_markerItemSignalMapper, SLOT(map()));
            m_markerItemSignalMapper.setMapping(markerItem, markerItem);
            connect(markerItem, SIGNAL(focusChanged()), this, SIGNAL(focusedMarkerChanged()));
        }
        else
            removedMarkerItems.removeOne(m_uuidMarkerItemMap[marker.uuid()]);
    }
    foreach(MarkerItem* markerItem, removedMarkerItems)
    {
        QUuid uuid = m_uuidMarkerItemMap.key(markerItem);
        m_uuidMarkerItemMap.remove(uuid);
        m_uuidMarkerMap.remove(uuid);
        removeItem(markerItem);
    }
}

void Timeline::markerXChanged(QObject* markerObject)
{
    MarkerItem* markerItem = static_cast<MarkerItem*>(markerObject);
    QUuid markerUuid = m_uuidMarkerItemMap.key(markerItem);

    Marker marker = m_uuidMarkerMap[markerUuid];
    marker.setPosition(fromSceneXPos(markerItem->pos().x()) / 2 * 2);
    //qDebug() << markerObject << marker.position();
    emit markerAdjusted(marker);
}

void Timeline::setFocusedMarker(Marker marker)
{
    QUuid uuid = m_uuidMarkerMap.key(marker);
    MarkerItem* markerItem = m_uuidMarkerItemMap.value(uuid);
    if (markerItem)
        markerItem->setFocus();
}

QList<Marker> Timeline::selectedMarkers() const
{
    QList<Marker> markers;
    foreach(QGraphicsItem* item, selectedItems())
    {
        markers.append(m_uuidMarkerMap[m_uuidMarkerItemMap.key(static_cast<MarkerItem*>(item))]);
    }

    return markers;
}

void Timeline::setActiveRange(Range range)
{
    if (!range.isValid())
    {
        delete m_activeRangeBar;
        m_activeRangeBar = NULL;
        return;
    }

    qreal width = toSceneXPos(range.upperMarker().position()) - toSceneXPos(range.lowerMarker().position());
    QRectF rangeRect(toSceneXPos(range.lowerMarker().position()), -20, width, 20);
    if (m_activeRangeBar)
        m_activeRangeBar->setRect(rangeRect);
    else
    {
        m_activeRangeBar = addRect(rangeRect);
        QLinearGradient linearGradient(0, -20, 0, 30);
        linearGradient.setColorAt(0.0, Qt::yellow);
        linearGradient.setColorAt(0.4, Qt::black);
        m_activeRangeBar->setBrush(linearGradient);
        m_activeRangeBar->setZValue(-1);
    }

}

Marker Timeline::focusedMarker() const
{
    QUuid focusedUuid = m_uuidMarkerItemMap.key(static_cast<MarkerItem*>(focusItem()));
    return m_uuidMarkerMap.value(focusedUuid);
}

void Timeline::focusPreviousMarker()
{
    QUuid focusedUuid = m_uuidMarkerItemMap.key(static_cast<MarkerItem*>(focusItem()));
    Marker focusedMarker = m_uuidMarkerMap.value(focusedUuid);
    QList<Marker> markers = m_uuidMarkerMap.values();
    qSort(markers);
    int index = markers.indexOf(focusedMarker);
    if (index > 0)
    {
        Marker nextMarker = markers[index - 1];
        m_uuidMarkerItemMap[nextMarker.uuid()]->setFocus();
    }
}

void Timeline::focusNextMarker()
{
    QUuid focusedUuid = m_uuidMarkerItemMap.key(static_cast<MarkerItem*>(focusItem()));
    Marker focusedMarker = m_uuidMarkerMap.value(focusedUuid);
    QList<Marker> markers = m_uuidMarkerMap.values();
    qSort(markers);
    int index = markers.indexOf(focusedMarker);
    if (index < markers.count() - 1)
    {
        Marker nextMarker = markers[index + 1];
        m_uuidMarkerItemMap[nextMarker.uuid()]->setFocus();
    }
}

